/**
 * @file 标签页服务（TabService）
 * @description
 *  - 统一注册并处理来自渲染进程的标签页相关 IPC 请求
 *  - 通过 global.tabMap 根据 webContentsId 定位标签对象并代理调用其方法
 *  - 仅在主进程初始化时创建一次（单例），避免重复注册 IPC 监听
 *  - 注意：tabTopic.get 使用 e.returnValue 同步返回标签序列化数据
 */
import { ipcMain, type IpcMainEvent } from 'electron'
import { tabTopic, toolbarTopic } from '~shared/ipc-topic'
import { Tab } from '#/browser/entities/tab.entity'

export class TabService {
  private static instance: TabService

  /**
   * 构造函数（私有）
   * - 初始化时注册所有与标签页相关的 IPC 监听
   * - 外部请通过 TabService.getInstance() 获取实例
   */
  private constructor() {
    this.registerIpcHandlers()
  }

  /**
   * 获取单例实例
   * 用法：在应用启动（app.whenReady）后调用一次，重复调用将复用已创建实例。
   */
  static getInstance(): TabService {
    if (!TabService.instance) {
      TabService.instance = new TabService()
    }
    return TabService.instance
  }

  /**
   * 根据事件或显式提供的 webContentsId 获取对应的标签对象
   * @param e IpcMainEvent（用于获取默认的 sender.id）
   * @param webContentsId 可选；不传时使用 e.sender.id
   * @returns 对应的标签对象（如无则为 undefined）
   */
  getTab(e: IpcMainEvent, webContentsId?: number): Tab | undefined {
    const contentsId = webContentsId ?? e.sender.id
    return global.tabMap.get(contentsId)
  }

  /**
   * 注册所有标签相关的 IPC 监听
   * 说明：请确保仅在构造时调用一次，避免重复注册导致的副作用。
   */
  registerIpcHandlers() {
    /**
     * 获取标签页数据（同步）
     * 作用：返回指定标签的可序列化数据对象
     * 参数：cid? 指定 webContentsId；未提供则使用 e.sender.id
     * 返回：通过 e.returnValue 同步返回 data
     */
    ipcMain.on(tabTopic.get, (e, cid?: number) => {
      e.returnValue = this.getTab(e, cid)?.data
    })

    /**
     * 获取焦点
     * */
    ipcMain.on(tabTopic.handle.focus, (e, cid?: number) => {
      this.getTab(e, cid)?.focus()
    })

    /**
     * 后退：等价于浏览器后退
     * 参数：cid? 指定目标标签
     */
    ipcMain.on(tabTopic.handle.back, (e, cid?: number) => {
      this.getTab(e, cid)?.goBack()
    })

    /**
     * 前进：等价于浏览器前进
     * 参数：cid? 指定目标标签
     */
    ipcMain.on(tabTopic.handle.forward, (e, cid?: number) => {
      this.getTab(e, cid)?.goForward()
    })

    /**
     * 刷新：重新加载当前页面
     * 参数：cid? 指定目标标签
     */
    ipcMain.on(tabTopic.handle.refresh, (e, cid?: number) => {
      this.getTab(e, cid)?.reload()
    })

    /**
     * 跳转到指定 URL
     * 参数：url 要打开的链接；cid? 指定目标标签
     */
    ipcMain.on(tabTopic.handle.navigate, (e, url?: string, cid?: number) => {
      this.getTab(e, cid)?.openUrl(url)
    })

    /**
     * 停止加载：终止当前网络请求/导航
     * 参数：cid? 指定目标标签
     */
    ipcMain.on(tabTopic.handle.stop, (e, cid?: number) => {
      this.getTab(e, cid)?.stop()
    })

    /**
     * 切换静音：开启/关闭页面音频输出
     * 参数：cid? 指定目标标签
     */
    ipcMain.on(tabTopic.handle.toggleMute, (e, cid?: number) => {
      this.getTab(e, cid)?.toggleMute()
    })

    /**
     * 切换历史记录记录开关
     * 参数：cid? 指定目标标签
     */
    ipcMain.on(tabTopic.handle.toggleHistoryEnabled, (e, cid?: number) => {
      this.getTab(e, cid)?.toggleHistoryEnabled()
    })

    /**
     * 设置标签内容渲染宽度
     * 参数：width 目标宽度（number）；cid? 指定目标标签
     */
    ipcMain.on(tabTopic.handle.setWidth, (e, width: number, cid?: number) => {
      this.getTab(e, cid)?.setWidth(width)
    })

    /**
     * 设置 ESC 优先级
     * 参数：priority 数值越大优先级越高；cid? 指定目标标签
     */
    ipcMain.on(tabTopic.handle.setEscPriority, (e, priority: number, cid?: number) => {
      this.getTab(e, cid)?.setEscPriority(priority)
    })

    /**
     * 切换 User-Agent（示例：桌面/移动 UA 切换）
     * 参数：cid? 指定目标标签
     */
    ipcMain.on(tabTopic.handle.toggleUserAgent, (e, cid?: number) => {
      this.getTab(e, cid)?.toggleUserAgent()
    })

    /**
     * 切换独立窗口模式：在独立窗口与当前容器间切换
     * 参数：cid? 指定目标标签
     */
    ipcMain.on(tabTopic.handle.toggleSeparateWindow, (e, cid?: number) => {
      this.getTab(e, cid)?.toggleInSeparateWindow()
    })

    /**
     * 切换固定（Pinned）状态
     * 参数：cid? 指定目标标签
     */
    ipcMain.on(tabTopic.handle.togglePinned, (e, cid?: number) => {
      this.getTab(e, cid)?.togglePinned()
    })

    /**
     * 翻译当前页面到指定语言
     * 参数：language 目标语言代码；cid? 指定目标标签
     */
    ipcMain.on(tabTopic.handle.translatePage, (e, language: string, cid?: number) => {
      this.getTab(e, cid)?.translatePage(language)
    })

    /**
     * 还原页面原文（取消翻译）
     * 参数：cid? 指定目标标签
     */
    ipcMain.on(tabTopic.handle.restoreOriginal, (e, cid?: number) => {
      this.getTab(e, cid)?.restoreOriginal()
    })

    /**
     * 翻译状态改变
     * */
    ipcMain.on(tabTopic.handle.tabTranslationState, (e, status: F2.tab.TranslationState) => {
      this.getTab(e)?.toggleTranslationState(status)
    })

    /**
     * 查找页面
     */
    ipcMain.on(
      tabTopic.handle.findInPage,
      (e, text: string, options: Electron.FindInPageOptions, webContentsId?: number) => {
        this.getTab(e, webContentsId)?.findInPage(text, options, e.sender)
      }
    )
    /**
     * 停止查找页面
     */
    ipcMain.on(tabTopic.handle.stopFindInPage, (e, webContentsId?: number) => {
      this.getTab(e, webContentsId)?.stopFindInPage(e.sender)
    })
    /**
     * 关闭tab
     * */
    ipcMain.on(tabTopic.handle.closeTab, (e, webContentsId?: number) => {
      this.getTab(e, webContentsId)?.close()
    })

    /**
     * 设置工具栏配置
     * 参数：config 工具栏配置对象；cid? 指定目标标签
     */
    ipcMain.on(tabTopic.handle.setToolbarConfig, (e, config: F2.toolbar.Config, cid?: number) => {
      const tab = this.getTab(e, cid)
      if (tab) {
        tab.setToolbarConfig(config)
      }
    })

    /**
     * 设置工具栏单击按钮
     * */
    ipcMain.on(toolbarTopic.buttonClick, (e, buttonId: string, cid?: number) => {
      const tab = this.getTab(e, cid)
      if (tab) {
        tab.toolbarButtonClick(buttonId)
      }
    })
  }
}
